/*----------------------------------------------------------------------*/
/* FAT file system test terminal for FatFs R0.07a  (C)ChaN, 2008        */
/* modified by Martin Thomas 4/2009 for the STM32 example               */
/*----------------------------------------------------------------------*/

#include <string.h>
#include <CoOS.h>
#include <stdio.h>
#include <diskio.h>

#include <rtc.h>
#include <stm32f10x.h>

//#include <DAC_STM32.h>
#include <ParseString.h>
#include <Fat_Func.h>

//define ofs address of WAV_infomation in file, and size of them
#define RIFF_start_ofs			0
#define RIFF_size				4
#define WAVE_start_ofs			RIFF_start_ofs + 0x8
#define WAVE_size				4
#define fmt_start_ofs			WAVE_start_ofs + 0x4
#define fmt_size				4
#define CompressCode_start_ofs 	fmt_start_ofs + 0x8
#define CompressCode_size 		2
#define NumOfChanels_start_ofs 	fmt_start_ofs + 0xa
#define NumOfChanels_size 		2
#define SampleRate_start_ofs	fmt_start_ofs + 0xc
#define SampleRate_size			4
#define BytePerSec_start_ofs	fmt_start_ofs + 0x10
#define BytePerSec_size			4
#define BitPerSample_start_ofs 	fmt_start_ofs + 0x16
#define BitPerSample_size 		2
#define data_start_ofs			fmt_start_ofs + 0x18
#define data_size				4
#define SampledData_start_ofs 	data_start_ofs + 0x8

unsigned long SampledData_ofs = SampledData_start_ofs;

extern USART_TypeDef* USARTx;
//DWORD acc_size; /* Work register for fs command */
//WORD acc_files, acc_dirs;
FILINFO Finfo;
#if _USE_LFN
char Lfname[512];
#endif

//char linebuf[120]; /* Console input buffer */

FATFS Fatfs[_DRIVES];
FIL File1;
//FIL File2;
DIR Dir;
BYTE Buff[4 * 1024] __attribute__ ((aligned (4)));
/* buffer for write*/

/***************************************************************************************************
 * Function Name : OpenFile
 * Input		 : file name
 * Output		 : 0: exist file, 1: new file
 * Description 	 : Open file on SD card
 ****************************************************************************************************/
int CreateFile(char* filename) {
	int status = 0;
	f_mount(0, &Fatfs[0]);
	if (f_open(&File1, filename, FA_READ) != FR_OK) {
		f_open(&File1, filename, FA_CREATE_NEW);
		status = 1;
	}
	f_close(&File1);
	return status;
}
/***************************************************************************************************
 *
 ****************************************************************************************************/
unsigned long WriteFile(char* filename, const char* data,unsigned long ofs) {
//	UINT s2 = sizeof(Buff);
	UINT s2;
	char tBuff[5];
	unsigned long start = 0,stop = 5;
	unsigned long len = strlen(data);
	f_open(&File1, filename, FA_WRITE);
	f_lseek(&File1, ofs);
	while(1)
	{
		substring(start,stop,data,tBuff);
		f_write(&File1, tBuff, strlen(tBuff), &s2);
		ofs = ofs + s2;
		if(stop >= len){
			break;
		}
		start =stop;
		stop = stop + 5;
	}
//	memcpy(Buff, (BYTE*) data, strlen(data) + 1);
//	f_write(&File1, Buff, strlen(data), &s2);
	f_close(&File1);
	return ofs;
}

/***************************************************************************************************
 *
 ****************************************************************************************************/
void AppendFile(char* filename, char* data) {
//	unsigned int size = 250;
//	DWORD size_total = 0;
//	USARTx = USARTTerm;
//	size_t str_size = 0;
//	f_open(&File1, filename, 1);
//	do {
//		f_lseek(&File1, size_total);
//
//		f_read(&File1, Buff, 3 * 1024, &size);
//
//		str_size = strlen((char*) Buff);
//		size_total = size_total + size;
//		if ((size == 0) && (str_size == 0)) {
//			break;
//		}
//	} while (size == str_size);
//	f_close(&File1);
//	WriteFile(filename, data, size_total);
}

/**********************************************************************************
 *
 **********************************************************************************/

unsigned int ReadFileText(char* filename, char* str, unsigned int size,
		DWORD ofs) {
	char tBuff[size + 1];
	ClearString(tBuff);
	f_open(&File1, filename, FA_READ);
	f_lseek(&File1, (DWORD) ofs);
	f_read(&File1, tBuff, size, &size);
	strcpy(str, tBuff);
	f_close(&File1);
	return size;
}

/**********************************************************************************
 *
 **********************************************************************************/
unsigned int ReadFileNonText(char* filename, void* str, unsigned int size,
		DWORD ofs) {
	ClearVariable(str);
	f_open(&File1, filename, FA_READ);
	f_lseek(&File1, (DWORD) ofs);
	f_read(&File1, str, size, &size);
	f_close(&File1);
	return size;
}

/********************************************************************
 * open dir
 *
 * put list of file (info) onto "FILINFO *List"
 * return: number of items under dir
 * 		   -1 open fail
 * 		   -2 read fail
 ********************************************************************/
int ListDir(const char *PATH, FILINFO *List) {
	unsigned int pos;
	FRESULT fres = f_chdir(PATH);
	if (f_opendir(&Dir, PATH) != 0) {
		return -1;
	}
	pos = 0;
	for (;;) {
		if (f_readdir(&Dir, &Finfo) != 0) {
			return -2;
		}
		if (strcmp(Finfo.fname, "") == 0) {
			List[pos] = Finfo;
			break;
		}
		List[pos++] = Finfo;
	}
	return pos - 1;
}

/*
 *
 */
unsigned int CheckIfFile(char* filename) {
	unsigned int res = 0;
	DIR dir_tmp;
	res = f_opendir(&dir_tmp, filename);
	if (res != 0) {
		return 1;
	} else {
		return 0;
	}
}

/*****************************************************************************
 * check if a file is a WAV file
 * return 0 if wrong
 * 		  1 if right, and return wav_info also
 *****************************************************************************/
unsigned int CheckIfWAV(char *filename, WAV_INFO* WAV_info) {
	char str_tmp[6];
	unsigned long tmp[4];
	ClearString(str_tmp);
	ClearVariable(tmp);
	ReadFileText(filename, str_tmp, RIFF_size, RIFF_start_ofs);
	if (strcmp(str_tmp, "RIFF") != 0) {
		return 0;
	}
	ReadFileText(filename, str_tmp, WAVE_size, WAVE_start_ofs);
	if (strcmp(str_tmp, "WAVE") != 0) {
		return 0;
	}
	ReadFileText(filename, str_tmp, fmt_size, fmt_start_ofs);
	if (strcmp(str_tmp, "fmt ") != 0) {
		return 0;
	}
	ReadFileNonText(filename, tmp, CompressCode_size, CompressCode_start_ofs);
	ReadFileNonText(filename, tmp, NumOfChanels_size, NumOfChanels_start_ofs);
	WAV_info->NumOfChannels = tmp[0];
	ReadFileNonText(filename, tmp, SampleRate_size, SampleRate_start_ofs);
	WAV_info->SampleRate = tmp[0];
	ReadFileNonText(filename, tmp, BytePerSec_size, BytePerSec_start_ofs);
	WAV_info->BytePerSec = tmp[0];
	ReadFileNonText(filename, tmp, BitPerSample_size, BitPerSample_start_ofs);
	unsigned int BitPerSample = tmp[0];
	while ((BitPerSample % 8) != 0) {
		if (BitPerSample > 32) {
			BitPerSample = 32;
			break;
		}
		BitPerSample++;
	}
	WAV_info->BytePerSample = BitPerSample / 8;
	ReadFileText(filename, str_tmp, data_size, data_start_ofs);
	if (strcmp(str_tmp, "data") != 0) {
		return 0;
	}
	strcpy(WAV_info->Name, filename);
	return 1;
}

void CloseWAVFile(WAV_INFO wav_info)
{
	f_open(&File1, wav_info.Name, FA_READ);
	f_close(&File1);
	SampledData_ofs = SampledData_start_ofs;
}

uint16_t ReadWAVFile(WAV_INFO wav_info, uint8_t *flag_end) {
	uint16_t res;
	char byte_data[4];
	long sampled_data = 0;
	unsigned int read_byte = 0;
	if (SampledData_ofs == SampledData_start_ofs) {
		f_open(&File1, wav_info.Name, FA_READ);
	}
	f_lseek(&File1, (DWORD) SampledData_ofs);
	f_read(&File1, byte_data, wav_info.BytePerSample, &read_byte);
	if (read_byte == 0) {
		SampledData_ofs = SampledData_start_ofs;
		f_close(&File1);
		OUTPUT_USARTTerm;
		puts("close file\r\n");
		*flag_end = 1;
	}
	SampledData_ofs = SampledData_ofs + read_byte
			+ (wav_info.NumOfChannels - 1) * wav_info.BytePerSample;
	if (wav_info.BytePerSample == 1) {
		/*
		 sampled_data = (byte_data[0] & (0xFF));
		 res = ((double) (sampled_data * 4095) / 0xFF);
		 */
		res = ((byte_data[0] & (0xFF)) * 4095) / 0xFF;
	} else if (wav_info.BytePerSample == 2) {
		/*
		 sampled_data = (byte_data[0] & (0xFF)) | ((byte_data[1]&(0xFF)) << 8);
		 sampled_data = (sampled_data + 0x7FFF);
		 res = ( ((sampled_data+ 0x7FFF) * 4095) / 0xFFFF);
		 */
		res = ((byte_data[0] & (0xFF)) | (byte_data[1] << 8)) * 4095 / 0xFFFF
				+ 2047;
	}
	/*else if (wav_info.BytePerSample == 3) {
	 sampled_data = (byte_data[0] & (0xFF)) | (byte_data[1] << 8)
	 | (byte_data[2] << 16);
	 res = (uint16_t)((double) (sampled_data * 4095) / 0xFFFFFF);
	 } else {
	 sampled_data = (byte_data[0] & (0xFF)) | (byte_data[1] << 8)
	 | (byte_data[2] << 16) | (byte_data[1] << 24);
	 res = (uint16_t)((double) (sampled_data * 4095) / 0xFFFFFFFF);
	 }*/
	return res - 205;
}

/*
 *
 */
void PathGoBack(char *PATH) {
	int pos = 0;
	for (pos = strlen(PATH) - 1; pos >= 0; pos--) {
		if (PATH[pos] == '/') {
			char path_tmp[128];
			substring(0, pos, PATH, path_tmp);
			strcpy(PATH, path_tmp);
			break;
		}
	}
}

/*******************************************************************************
 * mount sd card
 *
 * return 1 if OK
 * 		  0 if ERROR
 *******************************************************************************/
int MountingSDcard() {
	f_mount(0, &Fatfs[0]);
	FRESULT res = f_open(&File1, "0:NULL.txt", 10);
	if ((res == FR_NO_FILE) || (res == FR_OK)) {
		f_close(&File1);
		return 1;
	} else {
		return 0;
	}
}

